using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using igp.net.DataModel;

namespace igp.net.DataModel
{
    /// <summary>
    /// Represents a legend.
    /// </summary>
    public class IgpLegend : IgpItem
    {
        /// <summary>
        /// X coordinate - screen coordinates in pixels
        /// </summary>
        public int X { get; set; }

        /// <summary>
        /// Y coordinate - screen coordinates in piexels.
        /// </summary>
        public int Y { get; set; }

        private int Xo;
        
        private int Yo;

        /// <summary>
        /// Gets/Sets width in piexels.
        /// </summary>
        public int Width { get; set; }

        /// <summary>
        /// Gets/Sets height in pixels.
        /// </summary>
        public int Height { get; set; }

        /// <summary>
        /// Enables/Disables visibility of the legend.
        /// </summary>
        public bool Enabled { get; set; }

        private bool Edited;

        /// <summary>
        /// Gets/Sets background color.
        /// </summary>
        public Color BackgroundColor { get; set; }

        /// <summary>
        /// Gets/Sets border color.
        /// </summary>
        public Color FrameColor { get; set; }

        /// <summary>
        /// Gets/Sets text color.
        /// </summary>
        public Color TextColor { get; set; }

        /// <summary>
        /// Default constructor.
        /// </summary>
        public IgpLegend()
        {
            Defaults();
        }

        /// <summary>
        /// Sets all parameters to defaults.
        /// </summary>
        public void Defaults()
        {
            X = 20;
            Y = 20;
            Xo = 20;
            Yo = 20;
            Width = 0;
            Height = 0;
            Edited = false;
            Enabled = true;
            BackgroundColor = Color.White;
            FrameColor = Color.Black;
            TextColor = Color.Black;
        }

        /// <summary>
        /// Draws the legend on the screen.
        /// </summary>
        /// <param name="graph">Graphics object used for drawing</param>
        public override void Draw(Graphics graph)
        {
            if (!Enabled || IgpProject.Singleton.GetLegendCount() == 0) return;

            string longestString = "";
            List<IgpItem> validItems = new List<IgpItem>();
            
            foreach (IgpItem item in IgpProject.Singleton.Items)
            {
                if (item.VisibleOnLegend && (item.TypeID == IgpItemType.Polynomial || item.TypeID == IgpItemType.PointSet || item.TypeID == IgpItemType.Function))
                {
                    validItems.Add(item);

                    if (item.ItemName.Length > longestString.Length)
                    {
                        longestString = item.ItemName;    
                    }
                }
            }

            Width = 46 + (int)graph.MeasureString(longestString, igpSettings.Singleton.ChartFont).Width;
            Height = (int) ( (IgpProject.Singleton.GetLegendCount() + 0.5) * (igpSettings.Singleton.ChartFont.Size + 3));

            Rectangle rect = new Rectangle(X, Y, Width, Height);
            if (!Edited)
            {
                graph.FillRectangle(new SolidBrush(BackgroundColor), rect);
            }
            else
            {
                graph.FillRectangle(new SolidBrush(Color.FromArgb(150, 
                                                                  BackgroundColor.R, 
                                                                  BackgroundColor.G, 
                                                                  BackgroundColor.B)
                                        )
                                    , rect
                    );

                DrawCoordinates(graph);

            }
            graph.DrawRectangle(new Pen(FrameColor), rect);

            int index = 0;
            foreach (IgpItem item in validItems)
            {
                //Drawing Items

                Pen pn = new Pen(item.LineColor, item.LineWidth) {DashStyle = item.LineType};
                int lineY = (int) (Y + 2 + (igpSettings.Singleton.ChartFont.Size + 3) * (index + 0.5));
                graph.DrawLine(pn, X + Width - 38, lineY, X + Width - 2, lineY);

                if (item.TypeID == IgpItemType.PointSet)
                {
                    igpPointSet pointSet = (igpPointSet) item;
                    int x = X + Width - 20;
                    int y = lineY;
                    int Size = pointSet.PointSize;
                    Rectangle recta = new Rectangle(x - Size / 2, y - Size / 2, Size, Size);

                    Color fc = pointSet.FillColor;

                    //Square
                    if (pointSet.PointType == IgpPointType.Square)
                    {
                        graph.FillRectangle(new SolidBrush(fc), recta);
                        graph.DrawRectangle(new Pen(pointSet.FrameColor), recta);
                    }

                    //Circle
                    if (pointSet.PointType == IgpPointType.Circle)
                    {
                        graph.FillEllipse(new SolidBrush(fc), recta);
                        graph.DrawEllipse(new Pen(pointSet.FrameColor), recta);
                    }

                    //Cross
                    if (pointSet.PointType == IgpPointType.Cross)
                    {
                        graph.DrawLine(new Pen(pointSet.FrameColor, 2), x - Size / 2, y - Size / 2, x + Size / 2, y + Size / 2);
                        graph.DrawLine(new Pen(pointSet.FrameColor, 2), x - Size / 2, y + Size / 2, x + Size / 2, y - Size / 2);
                    }

                    //Triangle
                    if (pointSet.PointType == IgpPointType.Triangle)
                    {
                        Point[] pts = new Point[3];
                        pts[0].X = x - Size / 2;
                        pts[0].Y = y + Size / 2;
                        pts[1].X = x + Size / 2;
                        pts[1].Y = y + Size / 2;
                        pts[2].X = x;
                        pts[2].Y = y - Size / 2;

                        graph.FillPolygon(new SolidBrush(fc), pts);
                        graph.DrawPolygon(new Pen(pointSet.FrameColor), pts);
                    }

                }

                graph.DrawString(
                    item.ItemName,
                    igpSettings.Singleton.ChartFont,
                    new SolidBrush(TextColor),
                    X + 2,
                    Y + 2 + (igpSettings.Singleton.ChartFont.Size + 3) * index);
                index++;

            }
        }

        private void DrawCoordinates(Graphics graph)
        {
            graph.DrawString(
                "X:" + X,
                igpSettings.Singleton.ChartFont,
                new SolidBrush(IgpProject.Singleton.View.Axes.LineColor),
                Math.Min(Math.Max(X + 5, 25), IgpProject.Singleton.View.Width - 60),
                Math.Min(Math.Max(Y - 15, 5), IgpProject.Singleton.View.Height - 25));

            graph.DrawString(
                "Y:" + Y,
                igpSettings.Singleton.ChartFont,
                new SolidBrush(IgpProject.Singleton.View.Axes.LineColor),
                Math.Min(Math.Max(X + 35, 55), IgpProject.Singleton.View.Width - 30),
                Math.Min(Math.Max(Y - 15, 5), IgpProject.Singleton.View.Height - 25));

        }

        /// <summary>
        /// This method is required for item's reaction to mouse movement. 
        /// You must invoke this base method in your derived class in order 
        /// to update some useful properties.
        /// </summary>
        /// <param name="graph">Graphics object that can be used to paint something on the screen</param>
        /// <param name="e">Mouse Event Details</param>
        public override void InteractMove(Graphics graph, MouseEventArgs e)
        {
            base.InteractMove(graph, e);
            if (!Enabled) return;
            
            if (GetRect().Contains(e.X, e.Y) && !Edited && !InteractionInUse)
            {
                graph.DrawRectangle(new Pen(Color.Red), X, Y, Width, Height);
                DrawCoordinates(graph);
            }

            if (!Edited) return;

            X = Xo - (int)(VectorX / IgpProject.Singleton.View.GetRatioX());
            Y = Yo - (int)(VectorY / IgpProject.Singleton.View.GetRatioY());
        }

        /// <summary>
        /// This method is required for item's reaction to mouse buttons being pressed. 
        /// You must invoke this base method in your derived class in order 
        /// to update some useful properties.
        /// </summary>
        /// <param name="graph">Graphics object that can be used to paint something on the screen</param>
        /// <param name="e">Mouse Event Details</param>
        public override void InteractDown(Graphics graph, MouseEventArgs e)
        {
            base.InteractDown(graph, e);
            if (InteractionInUse) return;
            if (GetRect().Contains(e.X, e.Y) && e.Button == MouseButtons.Left)
            {
                Edited = true;
                InteractionInUse = true;
                Xo = X;
                Yo = Y;
            }
        }

        /// <summary>
        /// This method is required for item's reaction to mouse buttons being released. 
        /// </summary>
        /// <param name="graph">Graphics object that can be used to paint something on the screen</param>
        /// <param name="e">Mouse Event Details</param>
        public override void InteractUp(Graphics graph, MouseEventArgs e)
        {
            if (Edited) FormMain.Singleton.EditorWindow.ReadViewProperities();
            Edited = false;
            InteractionInUse = false;
        }

        private Rectangle GetRect()
        {
            double ratiox = IgpProject.Singleton.View.GetRatioX();
            double ratioy = IgpProject.Singleton.View.GetRatioY();
            return new Rectangle((int)(X * ratiox), (int)(Y * ratioy), (int)(Width * ratiox), (int)(Height * ratioy));
        }

        /// <summary>
        /// Saves data to a TextWriter.
        /// </summary>
        /// <param name="sw">data output</param>
        public override void SaveData(TextWriter sw)
        {
            sw.WriteLine("<legend>");

            sw.WriteLine("x = {0}", X);
            sw.WriteLine("y = {0}", Y);

            sw.WriteLine("enable = {0}", Enabled);

            sw.WriteLine("bgcolor = {0}", BackgroundColor.ToArgb());
            sw.WriteLine("frcolor = {0}", FrameColor.ToArgb());
            sw.WriteLine("txcolor = {0}", TextColor.ToArgb());

            sw.WriteLine("</legend>");
        }

        /// <summary>
        /// Loads data from a TextReader.
        /// </summary>
        /// <param name="sr">data input</param>
        public override void ReadData(TextReader sr)
        {
            String Line;
            while ((Line = sr.ReadLine()) != "</legend>")
            {
                char[] sep = { '=' };
                String[] cmd = Line.Split(sep, 2);

                if (cmd[0].StartsWith("x"))
                {
                    X = int.Parse(cmd[1]);
                }

                if (cmd[0].StartsWith("y"))
                {
                    Y = int.Parse(cmd[1]);
                }

                if (cmd[0].StartsWith("enable"))
                {
                    Enabled = bool.Parse(cmd[1]);
                }

                if (cmd[0].StartsWith("bgcolor"))
                {
                    BackgroundColor = Color.FromArgb(int.Parse(cmd[1]));
                }

                if (cmd[0].StartsWith("frcolor"))
                {
                    FrameColor = Color.FromArgb(int.Parse(cmd[1]));
                }

                if (cmd[0].StartsWith("txcolor"))
                {
                    TextColor = Color.FromArgb(int.Parse(cmd[1]));
                }
            }
        }
    }
}